#pragma once
#include "reactor/noncopyable.hpp"
#include <functional>
#include <vector>
#include <memory>
#include <mutex>
#include <thread>

namespace reactor {
class Channel;
class Epoll;

/**
 * @brief 事件循环，Reactor 模式的核心
 */
class EventLoop : noncopyable {
public:
    using Functor = std::function<void()>;

    EventLoop();
    ~EventLoop();

    // 启动事件循环
    void loop();
    // 退出事件循环
    void quit();

    // 在当前 IO 线程中执行 cb
    void runInLoop(Functor cb);
    // 把 cb 放入队列，并在 IO 线程中执行
    void queueInLoop(Functor cb);

    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);

    // 判断当前是否在 IO 线程
    bool isInLoopThread() const { return _threadId == std::this_thread::get_id(); }
    // 断言当前在 IO 线程，否则终止程序
    void assertInLoopThread();

private:
    void wakeup();
    void handleRead(); // 用于 wakeupFd
    void doPendingFunctors();

    bool _looping;
    bool _quit;
    bool _callingPendingFunctors;
    const std::thread::id _threadId;
    
    std::unique_ptr<Epoll> _poller;
    int _wakeupFd;
    std::unique_ptr<Channel> _wakeupChannel;

    std::mutex _mutex;
    std::vector<Functor> _pendingFunctors;
};
} // namespace reactor
